<?php
/**
 * Classe des armées de l'univers 1.
 *
 * @author jonathan <jo.link.noir@gmail.com>
 * @version 1.3: jo_link_noir
 * @date 06-07-2010
 */
class U1_Army extends SW_Structure_Single
{
	/** @var int */
	const TYPE = 2;

	/** @var string */
	const INDEX = 'army';

	/** @var string */
	const CLASS_ELEMENT = 'U1_Army_Element';

	/** @var string */
	const CLASS_EXCEPTION = 'U1_Army_Exception';

	/** @var int définit l'index à partir du quel les défense commmence*/
	const BORDER_DEFENSES = 100;


	/** @var int : Temps de construction réduit pour les éléments*/
	protected $reduceTime;


	/** @var array : contient les messages d'erreur*/
	public $errorMessages = array(
		0 => 'Erreur arme',
		1 => 'L\'élément doit être du type de ',
		2 => 'Arme non terminé',
		3 => 'Arme non débloqué',
		4 => 'Impossible de construire l\'arme',
		5 => 'Impossible d\'arrêter la construction de l\'arme',
		6 => 'Impossible de terminé l\'arme',
		7 => 'Arme déjà en construction',
		8 => 'Arme inexistante',
		9 => 'Liste de l\'arme inexistante',
		//100 -> SW_Structure_Single
		200 => 'Trop d\'armes en construction'
	);


	/**
	 * @param SW_Player $player
	 * @param int $idPlanet
	 */
	public function __construct(SW_Player $player, $idPlanet)
	{
		parent::__construct($player, $idPlanet, U1_Army_Dependency::factory(self::INDEX), U1_Army_DAO::getFactory(), self::CLASS_ELEMENT, self::CLASS_EXCEPTION);
	}

	/**
	 * @param SW_Structure_Element $element
	 * @return #field
	 * @exception U1_Army_Exception : Arme $group inexistant
	 */
	protected function initElement(SW_Structure_Element $element)
	{
		$cost = self::cost($element->getGroup(), $element->getLevel(), $this->player->getRace());
		if (null !== $cost)
		{
			$duration = self::duration($element->getGroup(), $element->getLevel(), $this->player->getRace());
			if (null !== $duration)
			{
				$element->setPrice($cost);
				$element->setDuration(intval($duration / $this->reduceTime));
				return $this;
			}
		}

		throw new $this->classException($this->errorMessages[8], 8);
	}

	/**
	 * @param int $id
	 * @param int $level
	 * @param int $race
	 * @return array | null
	 */
	static public function cost($id, $x, $race)
	{
		if (0 === $id)
		{
			$a = array(
				0 => 3000,
				1 => 1500
			);
		}
		else if (5 === $id)
		{
			$a = array(
				0 => 3000,
				1 => 1500
			);
		}
		else
			return null;

		//condition pour les races et arrondi du prix
		if (U1_Race::getIndex('werlingz') === $race)
			foreach ($a as &$v)
				$v = (int)($v * 0.95);

		return $a;
	}

	/**
	 * @param int $id
	 * @param int $level
	 * @param int $race
	 * @return int | null
	 */
	static public function duration($id, $x, $race)
	{
		if (0 === $id)		$d = 15000;
		else if (5 === $id)	$d = 15000;
		else return null;

		if (U1_Race::getIndex('werlingz') === $race)
			return (int)($d * 1.1);
		return (int)($d);
	}

	/**
	 * @param U1_Units $army
	 * @param bool $isAttack : si true initialise l'attaque et la défense en plus de la charge
	 * @return {minSpeed, freight, {consoHydro, consoAza}, {number_unity_h, number_unity_a}}
	 * @exception U1_Army_Exception
	 */
	static public function initUnitsAndGetInfos(U1_Units $army)
	{
		$fret = $consoH = $consoA = $nbH = $nbA = 0;
		$minSpeed = PHP_INT_MAX;
		foreach ($army as $group => $unity)
		{
			$hydro = $aza = 0;
			$count = $unity->getCount();
			if (0 === $group)
			{
				$freight = 400;
				$hydro = 2;
				$speed = 40;
			}
			else if (1 === $group)
			{
				$freight = 1000;
				$hydro = 2.5;
				$speed = 100;
			}
			else if (4 === $group)
			{
				$freight = 20;
				$hydro = 0.1;
				$speed = 50;
			}
			else if (5 === $group)
			{
				$freight = 80;
				$hydro = 2;
				$speed = 15;
			}
			else if (13 === $group)
			{
				$freight = 5000;
				$hydro = 10;
				$aza = 1;
				$speed = 100;
			}
			else
				throw new U1_Army_Exception('Arme '.$group.' inexistante, impossible de l\'initialiser');

			if ($hydro)
			{
				$consoH += $hydro * $count;
				$nbH += $count;
			}

			if ($aza)
			{
				$consoA += $aza * $count;
				$nbA += $count;
			}

			if ($minSpeed > $speed)
				$minSpeed = $speed;

			$unity->stats[U1_Unit::STAT_FREIGHT] = $freight;
			$fret += $freight * $count;
		}
		return array($minSpeed, $fret, array($consoH, $consoA), array($nbH, $nbA));
	}

	/**
	 * Remplit la variable stats des unités ({structure, defense, shied, attack, size})
	 * @param U1_Units $units
	 * @param  U1_Research $research = null
	 * @exception U1_Army_Exception
	 */
	public function initStats(U1_Units $units, U1_Research $research = null)
	{
		if ($research)
			$research = $this->getSiblingInstance(U1_Research::INDEX);

		foreach ($units as $g => $unit)
		{
			$stats =
				(0 === $g) ? array(
					30, 20, 0, 15, 10
				) : (
				(1 === $g) ? array(
					100, 50, 40, 10, 3
				) : (
				(4 === $g) ? array(
					10, 0, 0, 0, 1
				) : (
				(5 === $g) ? array(
					30, 30, 0, 50, 10
				) : (
				(5 === $g) ? array(
					200, 100, 40, 50, 100
				) : (
				null
			)))));

			if (!$stats)
				throw new U1_Army_Exception('Arme '.$g.' inexistante, impossible de l\'initialiser');

			if (isset($unit->stats[U1_Unit::STAT_FREIGHT]))
				$stats[U1_Unit::STAT_FREIGHT] = $unit->stats[U1_Unit::STAT_FREIGHT];
			$unit->stats = $stats;
		}
	}

	/**
	 * Calcule reduce_time, la durée à diviser aux arme
	 * @return float
	 */
	public function calculateReduceTime()
	{
		$building = $this->getSiblingInstance(U1_Building::INDEX);
		return 0.9
			+ pow($building->getLevelSumGroup(0), 2.5)
			+ pow($building->getLevelSumGroup(11)/2, 1.4)
			+ pow($this->getSiblingInstance(U1_Research::INDEX)->getLevelMaxGroup(10) / 3, 1.1);
	}

	/**
	 * Initialise les dépendances, calcule le reduce_time, initialise prix et la durée. Retourne l'id des éléments créés. Crée les éléments obligatorie s'il y en a.
	 */
	protected function _init()
	{
		$this->reduceTime = $this->calculateReduceTime();
		parent::_init();
	}

	/**
	 * Retourne true lorsque la structure peut construire un élément. Mais ne vérifie pas qu'un élément est constructible (rôle de elementCanBuild).
	 * @param int $timestamp
	 * @return bool|int : si int alors code d'erreur dans $errorMessages (true|200)
	 */
	public function structureCanBuild( $timestamp)
	{
		//des constructions en cours
		return (count($this->lists) > 15) ? 200 : parent::structureCanBuild( $timestamp);
	}

	/**
	 * @param bool $getDefenses = false ; si true alors les défenses seront inséré dans units
	 * @return U1_Units
	 */
	public function getUnits($getDefenses = false)
	{
		$units = new U1_Units();
		if ($getDefenses)
			foreach ($this->getLevelSumGroups() as $group => $count)
			{
				if ($count)
					$units->add(new U1_Unit($group, $count));
			}
		else
			foreach ($this->getLevelSumGroups() as $group => $count)
			{
				if (self::BORDER_DEFENSES > $group && $count)
					$units->add(new U1_Unit($group, $count));
			}
		return $units;
	}

	/**
	 * Fini la construction de la structure demander
	 * @param SW_Structure_List $list
	 * @param int $timestamp
	 * @exception U1_Building_Exception $this->classException
	 */
	protected function _finish(SW_Structure_List $list, $timestamp)
	{
		$this->player->addFinishElement($this, $list);
		parent::_finish($list, $timestamp);
	}

	public function __toString()
	{
		return self::INDEX;
	}
}